package threads;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import main.Constants;
import main.Game;
import main.GameFile;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import tasks.DownloadTask;
import tasks.TaskList;
import tasks.UploadTask;

public class TaskGenerator extends Thread {

	private ConcurrentLinkedQueue<TaskList> syncs;
	private Game game;
	
	private String session;

	public TaskGenerator(ConcurrentLinkedQueue<TaskList> syncs, Game g){
		this.syncs = syncs;
		this.game = g;
		this.session = Constants.SESSION;
	}

	@Override
	public void run() {
		//request filelist from server
		List<GameFile> serverFiles = getServerFiles(game.getGame());
		
		//compare serverfiles with local files
		TaskList result = compareWithLocalFiles(serverFiles);
		
		if(result!=null) syncs.offer(result);
	}

	private TaskList compareWithLocalFiles(List<GameFile> server) {
		List<GameFile> local = game.getFiles();
		if(server==null||local==null) return null;
		TaskList result = new TaskList(game.getGame(), game.getAbsPath());
		//process server list
		boolean found;
		Iterator<GameFile> it1 = server.iterator();
		while(it1.hasNext()){
			GameFile serverfile = it1.next();
			if(serverfile!=null){
				Iterator<GameFile> it2 = local.iterator();
				String ser_path = serverfile.getPathFile().toLowerCase();
				found = false;
				while(it2.hasNext()){
					GameFile localfile = it2.next();
					if(localfile!=null){
						//try to match
						String loc_path = localfile.getPathFile().toLowerCase();
						if(ser_path.equals(loc_path)){
							//matched -> find newer file
							long ser_time = serverfile.getModDate();
							long loc_time = localfile.getModDate();
							if(ser_time>loc_time){
								//download server file
								result.add(new DownloadTask(game.getAbsPath(),
										localfile.getPath(), 
										localfile.getFile(),
										game.getGame(),
										serverfile.getModDate(),
										serverfile.getSize()));
								result.addToSize(localfile.getSize());
							}else if(ser_time<loc_time){
								//upload local file
								result.add(new UploadTask(game.getAbsPath(), 
										localfile.getPath(), 
										localfile.getFile(),
										game.getGame(),
										localfile.getModDate(),
										localfile.getSize()));
								result.addToSize(localfile.getSize());
							}
							local.remove(localfile);
							found = true;
							break;
						}
					}
				}
				//no match for local file (add)
				if(!found) {
					result.add(
					new DownloadTask(game.getAbsPath(), serverfile.getPath(), 
							serverfile.getFile(), game.getGame(), 
							serverfile.getModDate(), serverfile.getSize()));
					result.addToSize(serverfile.getSize());
				}
						
			}
		}
		//process rest of local list
		Iterator<GameFile> it = local.iterator();
		while(it.hasNext()){
			GameFile loc = it.next();
			result.add(new UploadTask(game.getAbsPath(), loc.getPath(), 
					loc.getFile(), game.getGame(), loc.getModDate(), loc.getSize()));
			result.addToSize(loc.getSize());
		}
		return result;
	}

	private List<GameFile> getServerFiles(String gameName) {
		List<GameFile> serverFiles = new ArrayList<GameFile>();
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(Constants.HOST_URL+"filelist_game.php");
		try {
			//request
			List<NameValuePair> paras = new ArrayList<NameValuePair>();
			paras.add(new BasicNameValuePair("session", this.session));
			paras.add(new BasicNameValuePair("game", gameName));
			HttpEntity entity = new UrlEncodedFormEntity(paras, "UTF-8");
			post.setEntity(entity);
			
			//response
			HttpResponse res = client.execute(post);
			HttpEntity rEntity = res.getEntity();
			if(rEntity!=null){
				InputStream in = rEntity.getContent();
				BufferedReader rd = new BufferedReader(new InputStreamReader(in));
				String line;
				while((line=rd.readLine())!=null){
					try{
						String[] split = line.split("####");
						if(split.length==3){
							String relPath = split[0];
							long timestamp = Long.parseLong(split[1]);
							long filesize = Long.parseLong(split[2]);
							serverFiles.add(new GameFile(relPath, timestamp, filesize));
						}
					}catch(NumberFormatException e){
						e.printStackTrace();
					}
				}
				return serverFiles;
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}
